use std::{rc::Rc, cell::RefCell, ops::Deref};

use crate::{pool::{Pool, Handle}, function::render::rhi::Rhi, config::AliceConfig};

use image::*;
use super::{
    shader::Shader,
    texture::{Sampler, Texture}, material::Material, loader::Loader,
};


pub enum AssetType {
    Texture,
    Shader,
    Material,
    Audio,
    Script,
    Mesh,
    Animation
}


#[derive(Clone)]
pub struct AliceResource(Rc<RefCell<AliceResourceImpl>>);


impl Deref for AliceResource {
    type Target = Rc<RefCell<AliceResourceImpl>>;

    fn deref(&self) -> &Self::Target {
        &self.0
    }
}

impl AliceResource {
    pub fn new(rhi:Rhi,config:&AliceConfig) -> Self {
        Self(Rc::new(RefCell::new(AliceResourceImpl::new(rhi,config))))
    }
}


/// 资产管理模块
pub struct AliceResourceImpl {
    pub rhi: Rhi,
    /// Shader 池 ，管理应用中的 shader
    pub shader_pool:        Pool<Shader>,
    /// 采样器池， 管理应用中的纹理采样器 
    pub sampler_pool:       Pool<Sampler>,
    /// 纹理贴图池 ， 管理应用中的纹理贴图 
    pub texture_pool:       Pool<Texture>,
    /// 材质池， 管理应用中的所有材质
    pub material_pool:      Pool<Material>,
    /// 默认的纹理贴图的句柄，可以通过该句柄获取到默认贴图的引用 
    pub default_texture:    Handle<Texture>,
    /// 默认的采样器的句柄，可以通过该句柄获取到默认采样器的引用 
    pub default_sampler:    Handle<Sampler>,
    /// 默认的材质的句柄，可以通过该句柄获取到默认材质的引用 
    pub default_material:   Handle<Material>,
    pub loader:             Loader
}

impl AliceResourceImpl {
    pub fn new(rhi: Rhi,config:&AliceConfig) -> Self {

        let default_texture = Self::create_failed_texture(rhi.clone());

        let mut texture_pool = Pool::new();

        let default_texture = texture_pool.spawn(default_texture);

        let default_sampler = Self::create_default_sampler(rhi.clone());

        let mut sampler_pool = Pool::new();

        let default_sampler = sampler_pool.spawn(default_sampler);

        let mut material_pool = Pool::new();

        let default_material = material_pool.spawn(Material::default());

        let assets = config.get_project_root().join("assets");
        Self {
            rhi,
            shader_pool: Pool::new(),
            sampler_pool,
            texture_pool,
            material_pool,
            default_texture,
            default_sampler,
            default_material,
            loader:Loader::new(assets)
        }
    }
}

/// shader handle
impl AliceResourceImpl {
    // pub fn create_shader(&mut self, path: &'static str,label:Option<&'static str>) -> Handle<Shader> {
    //     let shader = Shader::new(self.rhi.clone(), path, label);
    //     self.shader_pool.spawn(shader)
    // }

    // pub fn create_default_shader(rhi:Rhi) -> Shader {
    //     let shader = Shader::new(self.rhi.clone(), path, label);
    //     self.shader_pool.spawn(shader)

    // }
}

/// texture handle
impl AliceResourceImpl {
    pub fn create_texture(&mut self, path: &'static str,label:Option<&'static str>) -> Handle<Texture> {
        let texture = Texture::from_path(self.rhi.clone(), path, label);

        self.texture_pool.spawn(texture)
    }

    pub fn create_failed_texture(rhi:Rhi) -> Texture {
        // let mut buffer: ImageBuffer<Rgba<u8>, Vec<u8>> = ImageBuffer::new(1, 1);

        // buffer.put_pixel(0, 0, Rgba([255, 255, 255, 255]));
        // let img = DynamicImage::ImageRgba8(buffer);

        let mut img: DynamicImage;
        img = image::open("assets/1.png").expect("load texture failed");
        img = img.flipv();


        Texture::from_image(rhi, &img, "default_texture.png", Some("default_texture"))

    }

    pub fn get_texture(&self,handle:Handle<Texture>) -> &Texture {
        self.texture_pool.borrow(handle)
    }

    pub fn get_textures(&self , handles:Vec<Handle<Texture>>) -> Vec<&Texture> {
        let mut textures = Vec::new();

        for handle in handles {
            textures.push(self.get_texture(handle))
        }

        textures

    }
}

/// sampler handle
impl AliceResourceImpl {

    pub fn create_default_sampler(rhi:Rhi) -> Sampler {
        Sampler::new(rhi, "standard sampler")
    }

    pub fn get_default_sampler(&self) -> &Sampler {
        self.sampler_pool.borrow(self.default_sampler)
    }
}


